﻿<!DOCTYPE html>
<html>
<head>
    <title>Canvas Drag</title>
    <script src="../Javascript/jquery-1.8.0.min.js"></script>
</head>
<body style="-webkit-user-select: none;">
    <canvas id='cnv' style="border: 1px solid Blue;" width="600" height="400"></canvas>
    <br />
    <input id="Button1" type="button" value="Pen" onclick="Selector.unregist(); Pen.regist();" />
    <input id="Button2" type="button" value="Selector" onclick="Pen.unregist(); Selector.regist()" />
    <input id="Button3" type="button" value="Clear" onclick="Clear();" />

    <script type="text/javascript">
        Array.prototype.removeIndex = function (index) {
            this.splice(index, 1);
        }

        var cmdArray = new Array();
        var ctx = document.getElementById('cnv').getContext('2d');
        function LineCommand(x, y, z, t) {
            this.PosX = x;      //左上角坐标
            this.PosY = y;      //左上角坐标
            this.RangeX = 0;    //范围宽度
            this.RangeY = 0;    //范围高度
            this.IndexZ = z;    //纵向位置
            this.PointList = new Array();   //节点列表
            this.Thickness = t; //粗细
            this.push = function (struct) {
                this.PointList.push(struct);
            };
            this.PointList.push([0, 0]);
            this.end = function () {
                var minOffsetX = 0;
                var minOffsetY = 0;
                for (var i = 0; i < this.PointList.length; i++) {
                    minOffsetX = this.PointList[i][0] < minOffsetX ? this.PointList[i][0] : minOffsetX;
                    minOffsetY = this.PointList[i][1] < minOffsetY ? this.PointList[i][1] : minOffsetY;
                    this.RangeX = this.PointList[i][0] > this.RangeX ? this.PointList[i][0] : this.RangeX;
                    this.RangeY = this.PointList[i][1] > this.RangeY ? this.PointList[i][1] : this.RangeY;
                }
                this.PosX += minOffsetX;
                this.PosY += minOffsetY;
                this.RangeX -= minOffsetX;
                this.RangeY -= minOffsetY;
                for (var i = 0; i < this.PointList.length; i++) {
                    this.PointList[i][0] -= minOffsetX;
                    this.PointList[i][1] -= minOffsetY;
                }
                var tmpi = 2;
                while (tmpi < this.PointList.length) {
                    if (
                    ((this.PointList[tmpi][0] - this.PointList[tmpi - 1][0]) == 0 && (this.PointList[tmpi - 1][0] - this.PointList[tmpi - 2][0]) == 0) ||
                    ((this.PointList[tmpi][1] - this.PointList[tmpi - 1][1]) == 0 && (this.PointList[tmpi - 1][1] - this.PointList[tmpi - 2][1]) == 0) ||
                    (((this.PointList[tmpi][0] - this.PointList[tmpi - 1][0]) / (this.PointList[tmpi][1] - this.PointList[tmpi - 1][1])) ==
                    ((this.PointList[tmpi - 1][0] - this.PointList[tmpi - 2][0]) / (this.PointList[tmpi - 1][1] - this.PointList[tmpi - 2][1])))) {
                        this.PointList.removeIndex(tmpi - 1);
                    } else {
                        tmpi++;
                    }
                }
            };
            this.IsMouseOver = function (x, y) {
                //首先，如果鼠标坐标不在范围内直接返回false
                var thicknessR = Math.ceil(this.Thickness / 2);
                if (x < this.PosX - thicknessR || x > this.PosX + this.RangeX + thicknessR || y < this.PosY - thicknessR || y > this.PosY + this.RangeY + thicknessR) return false;
                //细致判断鼠标坐标是否在路径上
                x -= this.PosX; y -= this.PosY;
                for (var i = 1; i < this.PointList.length; i++) {
                    var p1 = [this.PointList[i - 1][0], this.PointList[i - 1][1]];
                    var p2 = [this.PointList[i][0], this.PointList[i][1]];
                    //先粗略判断点击点是否在该线段的矩形范围内
                    if (x < Math.min(p1[0], p2[0]) - thicknessR || x > Math.max(p1[0], p2[0]) + thicknessR || y < Math.min(p1[1], p2[1]) - thicknessR || y > Math.max(p1[1], p2[1]) + thicknessR) { continue; }
                    //在通过点到直线距离等方法计算点击点是否在该线段上
                    var l = Math.abs((p1[0] - x) * (p2[1] - y) - (p1[1] - y) * (p2[0] - x)) / Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2)); //点击点到线段的距离
                    var len = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);  //线段长度平方
                    var lenP1 = Math.pow(x - p1[0], 2) + Math.pow(y - p1[1], 2); 		//点击点到P1的距离平方
                    var lenP2 = Math.pow(x - p2[0], 2) + Math.pow(y - p2[1], 2); 		//点击点到P2的距离平方
                    if ((l <= thicknessR && len > lenP1 && len > lenP2) || (lenP1 <= Math.pow(thicknessR, 2)) || (lenP2 <= Math.pow(thicknessR, 2))) {
                        return true;
                    }
                }
                return false;
            };
            this.draw = function () {
                ctx.lineWidth = this.Thickness;
                ctx.moveTo(this.PosX + this.PointList[0][0], this.PosY + this.PointList[0][1]);
                ctx.beginPath();
                for (var i = 0; i < this.PointList.length; i++) {
                    ctx.lineTo(this.PointList[i][0] + this.PosX, this.PointList[i][1] + this.PosY);
                }
                ctx.stroke();
                ctx.closePath();
            };
            this.move = function (x, y) {
                this.PosX = x;
                this.PosY = y;
            }
        }

        var cmdLine;

        var Pen = {
            mousedown: function () {
                var currentX = event.clientX - $('#cnv').offset().left + $(window).scrollLeft();
                var currentY = event.clientY - $('#cnv').offset().top + $(window).scrollTop();
                cmdLine = new LineCommand(currentX, currentY, 0, 10);
                cmdArray.push(cmdLine);
                //document.getElementById('cnv').addEventListener('mousemove', Pen.mousemove);
                document.onmousemove = function (event) {
                    var currentX = event.clientX - $('#cnv').offset().left + $(window).scrollLeft();
                    var currentY = event.clientY - $('#cnv').offset().top + $(window).scrollTop();
                    cmdLine.PointList.push([currentX - cmdLine.PosX, currentY - cmdLine.PosY]);
                }
                document.onmouseup = function (event) {
                    document.onmousemove = null;
                    cmdLine.end();
                    //event.preventDefault();
                }
            },
            mousemove: function () {
                var currentX = event.clientX - $('#cnv').offset().left + $(window).scrollLeft();
                var currentY = event.clientY - $('#cnv').offset().top + $(window).scrollTop();
                cmdLine.PointList.push([currentX - cmdLine.PosX, currentY - cmdLine.PosY]);
            },
            mouseup: function () {
                cmdLine.end();
                document.getElementById('cnv').removeEventListener('mousemove', Pen.mousemove)
            },
            regist: function () {
                document.getElementById('cnv').addEventListener('mousedown', this.mousedown);
                //document.getElementById('cnv').addEventListener('mouseup', this.mouseup);
            },
            unregist: function () {
                document.getElementById('cnv').removeEventListener('mousedown', this.mousedown);
                document.getElementById('cnv').removeEventListener('mouseup', this.mouseup);
            }
        };

        var Selector = {
            currentTarget: null,
            offsetX: 0,
            offsetY: 0,
            mousedown: function () {
                var currentX = event.clientX - $('#cnv').offset().left + $(window).scrollLeft();
                var currentY = event.clientY - $('#cnv').offset().top + $(window).scrollTop();
                for (var i = 0; i < cmdArray.length; i++) {
                    if (cmdArray[i].IsMouseOver(currentX, currentY)) {
                        Selector.currentTarget = cmdArray[i];
                        Selector.offsetX = currentX - Selector.currentTarget.PosX;
                        Selector.offsetY = currentY - Selector.currentTarget.PosY;

                        document.onmousemove = function (event) {
                            if (Selector.currentTarget != null) {
                                var currentX = event.clientX - $('#cnv').offset().left + $(window).scrollLeft();
                                var currentY = event.clientY - $('#cnv').offset().top + $(window).scrollTop();
                                Selector.currentTarget.move(currentX - Selector.offsetX, currentY - Selector.offsetY);
                            }
                        }
                        document.onmouseup = function (event) {
                            document.onmousemove = null;
                            Selector.currentTarget = null;
                            event.preventDefault();
                        }
                    }
                }
                //event.preventDefault();
            },
            mousemove: function () {
                if (this.currentTarget != null) {
                    var currentX = event.clientX - $('#cnv').offset().left + $(window).scrollLeft();
                    var currentY = event.clientY - $('#cnv').offset().top + $(window).scrollTop();
                    this.currentTarget.move(currentX - this.offsetX, currentY - this.offsetY);
                }
            },
            mouseup: function () {
                this.currentTarget = null;
                document.getElementById('cnv').removeEventListener('mousemove', this.mousemove);
                //event.preventDefault();
            },
            regist: function () {
                document.getElementById('cnv').addEventListener('mousedown', this.mousedown);
                //document.getElementById('cnv').addEventListener('mousemove', this.mousemove);
                //document.getElementById('cnv').addEventListener('mouseup', this.mouseup);
            },
            unregist: function () {
                document.getElementById('cnv').removeEventListener('mousedown', this.mousedown);
                //document.getElementById('cnv').removeEventListener('mouseup', this.mouseup);
            }
        };

        var needCheck = false;
        function Check() {
            needCheck = needCheck ? false : true;
            if (needCheck) {
                document.getElementById("Button1").disabled = 'disabled';
                document.getElementById("Button2").disabled = 'disabled';
            } else {
                document.getElementById("Button1").removeAttribute('disabled');
                document.getElementById("Button2").removeAttribute('disabled');
            }
        }

        function DrawCanvas() {
            for (var i = 0; i < cmdArray.length; i++) {
                cmdArray[i].draw();
            }
            if (needCheck) {
                var a = ctx.globalAlpha;
                var f = ctx.fillStyle;
                ctx.globalAlpha = 0.5;
                ctx.fillStyle = 'Red';
                var t1 = new Date();
                for (var w = 0; w < document.getElementById("cnv").width; w++) {
                    for (var h = 0; h < document.getElementById("cnv").height; h++) {
                        for (var i = 0; i < cmdArray.length; i++) {
                            if (cmdArray[i].IsMouseOver(w, h)) {
                                ctx.fillRect(w, h, 1, 1);
                            }

                        }
                    }
                }
                var t2 = new Date();
                console.log(t1.getTime() - t1.getTime());

                ctx.fillStyle = f;
                ctx.globalAlpha = a;
            }
        }
        ctx.lineJoin = 'bevel';
        ctx.lineCap = 'round';
        setInterval(function () {
            ctx.clearRect(0, 0, document.getElementById("cnv").width, document.getElementById("cnv").height);
            DrawCanvas();
        }, 40);

        function Clear() {
            cmdArray.length = 0;
        }

    </script>
</body>
</html>
